﻿using System;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
using System.Data.SqlClient;
using System.Diagnostics;
using System.Drawing.Imaging;
using System.IO;
using System.Runtime.InteropServices;
using System.Threading;
using Microsoft.Expression.Encoder;
using Microsoft.Expression.Encoder.Devices;
using Microsoft.Expression.Encoder.Live;
using RawInput_dll;
using log4net;

[assembly: log4net.Config.XmlConfigurator(Watch = true)]
namespace Sekolah
{
    public partial class Form1 : Form
    {
        #region rawinput
        private readonly RawInput _rawinput;

        const bool CaptureOnlyInForeground = true;

        private string buffer = string.Empty;
        private void OnKeyPressed(object sender, RawInputEventArg e)
        {
            if (UsbDevice.ParseKeyboardId(e.KeyPressEvent.DeviceName).Equals(_cardReaderId) && ContainsFocus)
            {
                _rawinput.AddMessageFilter();
                if (e.KeyPressEvent.KeyPressState == "BREAK")
                {
                    buffer += ((char) (e.KeyPressEvent.VKey)).ToString();
                    if (buffer.EndsWith("\r"))
                    {
                        buffer = buffer.Replace("\r", "").Replace("\n", "");
                        //label1.Text = buffer;
                        card_tap(buffer);
                        buffer = string.Empty;
                    }
                }
            }
            else
            {
                _rawinput.RemoveMessageFilter();
            }
        }
        #endregion

        #region Fields
        private const string DEFAULT_VIDEO_DEVICE_VALUE = "Screen Capture Source";
        private string _videoDeviceName;

        private const string DEFAULT_CARD_READER_VALUE = @"VID_13BA&PID_0018";
        private string _cardReaderId;

        private const string DEFAULT_DATABASE_CONNECTION_VALUE = @"Data Source=localhost;Initial Catalog=AdmSekolah;Persist Security Info=True;User ID=sa;Password=123";
        private string _databaseConnection;

        private const string TEMPEL_KARTU = "SILAKAN TEMPELKAN KARTU ID ANDA";
        private const string DATANG = "DATANG";
        private const string PULANG = "PULANG";

        private string _datang1, _datang2, _pulang1, _pulang2;
        private int _currentDate;

        private bool _tapColor;

        #endregion

        public Form1()
        {
            Log.Info("ABSEN APP STARTED");
            InitializeComponent();

            /*rawinput*/
            _rawinput = new RawInput(Handle, CaptureOnlyInForeground);
            _rawinput.KeyPressed += OnKeyPressed;

            try
            {
                _videoDeviceName = AppConfig.ReadSetting(AppConfig.VIDEO_DEVICE_KEY);
            }
            catch (Exception ex)
            {
                Log.Error(ex, ex.Message);
                AppConfig.AddUpdateAppSettings(AppConfig.VIDEO_DEVICE_KEY, DEFAULT_VIDEO_DEVICE_VALUE);
                _videoDeviceName = AppConfig.ReadSetting(AppConfig.VIDEO_DEVICE_KEY);
            }

            try
            {
                _cardReaderId = AppConfig.ReadSetting(AppConfig.CARD_READER_KEY);
            }
            catch (Exception ex)
            {
                Log.Error(ex, ex.Message);
                AppConfig.AddUpdateAppSettings(AppConfig.CARD_READER_KEY, DEFAULT_CARD_READER_VALUE);
                _cardReaderId = AppConfig.ReadSetting(AppConfig.CARD_READER_KEY);
            }

            try
            {
                _databaseConnection = AppConfig.ReadSetting(AppConfig.DATABASE_KEY);
            }
            catch (Exception ex)
            {
                Log.Error(ex, ex.Message);
                AppConfig.AddUpdateAppSettings(AppConfig.DATABASE_KEY, DEFAULT_DATABASE_CONNECTION_VALUE);
                _databaseConnection = AppConfig.ReadSetting(AppConfig.DATABASE_KEY);
            }
        }

        private void card_tap(string card_id)
        {
            if (!string.IsNullOrEmpty(card_id))
            {
                try
                {
                    string sql = "sp_card_tap '" + card_id + "'";
                    using (var da = new SqlDataAdapter(sql, _databaseConnection))
                    {
                        var dt = new DataTable();
                        da.Fill(dt);

                        if (dt.Rows.Count > 0)
                        {
                            string tapId = dt.Rows[0]["ID"].ToString();
                            string noInduk = dt.Rows[0]["NOMOR_INDUK"].ToString();
                            string waktu = dt.Rows[0]["WAKTU"].ToString();
                            string tipe = dt.Rows[0]["TIPE"].ToString();
                            string nama = dt.Rows[0]["NAMA"].ToString();
                            string jabatan = dt.Rows[0]["JABATAN"].ToString();
                            string masaKerja = dt.Rows[0]["MASAKERJA"].ToString();
                            if (tipe.ToUpper() == "SISWA")
                            {
                                textBox4.AppendText(DateTime.Now.ToString("HH:mm:ss") + " - " + noInduk + Environment.NewLine);
                            }
                            else if (tipe.ToUpper() == "GURU")
                            {
                                textBox3.AppendText(DateTime.Now.ToString("HH:mm:ss") + " - " + noInduk + Environment.NewLine);
                                if (label10.Text == DATANG || label10.Text == PULANG)
                                {
                                    lblNama.Text = "Nama : " + nama;
                                    lblJabatan.Text = "Jabatan : " + jabatan;
                                    lblWaktu.Text = "Waktu : " + DateTime.Parse(waktu).ToString("HH:mm:ss");

                                    Thread t = new Thread(() =>
                                    {
                                        cmdGrabImage_Click(tapId);
                                    });
                                    t.Start();
                                }
                                else
                                {
                                    var dlg = new MenuAbsenForm(nama, noInduk, masaKerja, label10.Text);
                                    dlg.ShowDialog(this);
                                }
                            }
                        }
                        else
                        {
                            textBox3.AppendText(DateTime.Now.ToString("HH:mm:ss") + " - " + card_id + Environment.NewLine);
                        }
                    }
                }
                catch (Exception ex)
                {
                    Log.Error(ex, ex.Message);
                    textBox3.AppendText(DateTime.Now.ToString("HH:mm:ss") + " - " + card_id + " Error : " + ex.Message + Environment.NewLine);
                }
            }
        }

        private void resetLabelAbsen()
        {
            lblNama.Text = "Nama : ";
            lblJabatan.Text = "Jabatan : ";
            lblWaktu.Text = "Waktu : ";
        }

        private void updateUlangTahun()
        {
            try
            {
                label4.Visible = false;
                label5.Visible = false;
                pictureBox3.Visible = false;
                string sql = "sp_card_ulangtahun";
                using (var da = new SqlDataAdapter(sql, _databaseConnection))
                {
                    var dt = new DataTable();
                    da.Fill(dt);

                    if (dt.Rows.Count > 0)
                    {
                        if (dt.Rows[0]["nama"] != DBNull.Value)
                        {
                            label5.Text = dt.Rows[0]["nama"].ToString();
                        }

                        if (dt.Rows[0]["FileData"] != DBNull.Value)
                        {
                            var ms = new MemoryStream((byte[])(dt.Rows[0]["FileData"]));
                            pictureBox3.BackgroundImage = Image.FromStream(ms);
                        }
                        label4.Visible = true;
                        label5.Visible = true;
                        pictureBox3.Visible = true;
                    }
                }
            }
            catch (Exception ex)
            {
                Log.Error(ex, ex.Message);
                //MessageBox.Show(ex.Message);
                textBox4.AppendText(ex.Message);
            }
            
        }

        private void updateWaktu(string hari)
        {
            _datang1 = null;
            _datang2 = null;
            _pulang1 = null;
            _pulang2 = null;
            _currentDate = DateTime.Now.Day;

            string sql = "select DATANG_1, DATANG_2, PULANG_1, PULANG_2 from CARD_WAKTU where HARI='" + hari + "'";
            using (var da = new SqlDataAdapter(sql, _databaseConnection))
            {
                var dt = new DataTable();
                da.Fill(dt);

                if (dt.Rows.Count > 0)
                {
                    if (dt.Rows[0]["DATANG_1"] != DBNull.Value)
                    {
                        _datang1 = dt.Rows[0]["DATANG_1"].ToString();
                    }

                    if (dt.Rows[0]["DATANG_2"] != DBNull.Value)
                    {
                        _datang2 = dt.Rows[0]["DATANG_2"].ToString();
                    }

                    if (dt.Rows[0]["PULANG_1"] != DBNull.Value)
                    {
                        _pulang1 = dt.Rows[0]["PULANG_1"].ToString();
                    }

                    if (dt.Rows[0]["PULANG_2"] != DBNull.Value)
                    {
                        _pulang2 = dt.Rows[0]["PULANG_2"].ToString();
                    }
                }
            }
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            label1.Text = DateTime.Now.ToString("dddd, dd MMMM yyyy", new System.Globalization.CultureInfo("id-ID"));
            label2.Text = TEMPEL_KARTU;
            CameraOn();

            int iklanBorder = 2;
            int iklanWidth = (panelIklan.Width - (4 * iklanBorder)) / 3;
            iklan1.Width = iklanWidth;
            iklan2.Width = iklanWidth;
            iklan3.Width = iklanWidth;
            iklan1.Left = iklanBorder;
            iklan2.Left = iklan1.Right + iklanBorder;
            iklan3.Left = iklan2.Right + iklanBorder;
        }

        private void Form1_SizeChanged(object sender, EventArgs e)
        {
            //analogClock1.Width = (int)(_clockWidthRatio * Width);
            //analogClock1.Height = (int)(_clockHeightRatio * Height);
        }

        private TimeSpan parseTime(string strTime)
        {
            var time = strTime.Split(':');
            int hour = int.Parse(time[0]);
            int minute = int.Parse(time[1]);
            int second = int.Parse(time[2]);
            return new TimeSpan(hour, minute, second);
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            try
            {
                if (_currentDate != DateTime.Now.Day)
                {
                    updateWaktu(DateTime.Now.ToString("dddd", new System.Globalization.CultureInfo("id-ID")));
                    updateUlangTahun();
                }

                label10.Text = string.Empty;
                analogClock1.Time = DateTime.Now;
                if (_datang1 != null && _datang2 != null && DateTime.Now.TimeOfDay >= parseTime(_datang1) && DateTime.Now.TimeOfDay < parseTime(_datang2))
                {
                    label10.Text = DATANG;
                }
                else if (_pulang1 != null && _pulang2 != null && DateTime.Now.TimeOfDay >= parseTime(_pulang1) && DateTime.Now.TimeOfDay < parseTime(_pulang2))
                {
                    label10.Text = PULANG;
                }
            }
            catch (Exception ex)
            {
                Log.Error(ex, ex.Message);
                timer1.Enabled = false;
            }            
        }

        private void timer2_Tick(object sender, EventArgs e)
        {
            _tapColor = !_tapColor;
            label2.BackColor = _tapColor ? Color.Red : Color.Green;
            pictureBox2.BackColor = label2.BackColor;
        }

        private void userLogin(string userName, string password)
        {
            try
            {
                userName = userName.Replace("'", "''");
                password = password.Replace("'", "''");
                string sql = "sp_card_login '" + userName + "', '" + password + "'";

                using (var da = new SqlDataAdapter(sql, _databaseConnection))
                {
                    var dt = new DataTable();
                    da.Fill(dt);

                    if (dt.Rows.Count > 0)
                    {
                        string status = dt.Rows[0]["STATUS"].ToString();
                        if (status.ToLower() == "pegawai")
                        {
                            var dlg = new MenuAbsenForm(dt.Rows[0]["NAMA"].ToString(), dt.Rows[0]["NIP"].ToString(), dt.Rows[0]["MASAKERJA"].ToString(), label10.Text);
                            dlg.ShowDialog(this);
                        }
                        else
                        {
                            var dlg = new FormPSB(dt.Rows[0]["NAMA"].ToString(), dt.Rows[0]["NO_FORMULIR"].ToString(), dt.Rows[0]["TAHUN_AJARAN"].ToString());
                            dlg.ShowDialog(this);
                        }
                        textBox1.Text = string.Empty;
                        textBox2.Text = string.Empty;
                    }
                    else
                    {
                        MessageBox.Show(this, "Username atau password salah.", "Login Gagal", MessageBoxButtons.OK,
                            MessageBoxIcon.Stop);
                    }
                }
            }
            catch (Exception ex)
            {
                Log.Error(ex, ex.Message);
                MessageBox.Show("Koneksi ke database gagal : " + ex.Message);
            }            
        }

        private void adminLogin(string userName, string Password)
        {
            if (Password != "19791117")
            {
                return;
            }

            timer1.Enabled = false;
            var dlg = new AdminForm();
            dlg.ShowDialog(this);
            _videoDeviceName = AppConfig.ReadSetting(AppConfig.VIDEO_DEVICE_KEY);
            _cardReaderId = AppConfig.ReadSetting(AppConfig.CARD_READER_KEY);
            _databaseConnection = AppConfig.ReadSetting(AppConfig.DATABASE_KEY);
            timer1.Enabled = true;
            try
            {
                CameraOn();
            }
            catch (Exception ex)
            {
                Log.Error(ex, ex.Message);
                MessageBox.Show("Gagal menyalakan kamera, mohon periksa konfigurasi / pilihan hardware.");
            }
        }

        private void button1_Click(object sender, EventArgs e)
        {
            string userName = textBox1.Text;
            string password = textBox2.Text;
            if (string.IsNullOrEmpty(userName) || string.IsNullOrEmpty(password))
            {
                return;
            }

            if (userName.ToLower().Equals("admin"))
            {
                adminLogin(userName, password);
            }
            else
            {
                userLogin(userName, password);
            }
        }

        #region camera

        private LiveJob _job;
        private LiveDeviceSource _deviceSource;

        private EncoderDevice getDevice(EncoderDeviceType type, string name)
        {
            var list = EncoderDevices.FindDevices(type);
            return list.FirstOrDefault(device => device.Name.ToLower() == name.ToLower());
        }

        private void CameraOn()
        {
            EncoderDevice video = getDevice(EncoderDeviceType.Video, _videoDeviceName);
            StopJob();

            if (video == null)
            {
                throw new EncodeErrorException("No Video/Audio capture devices have been found.");
            }

            // Starts new job for preview window
            _job = new LiveJob();

            // Create a new device source. We use the first audio and video devices on the system
            _deviceSource = _job.AddDeviceSource(video, null);
            _deviceSource.PickBestVideoFormat(new Size(640, 480), 15);

            // Get the properties of the device video
            SourceProperties sp = _deviceSource.SourcePropertiesSnapshot();

            // Resize the preview panel to match the video device resolution set
            panelVideoPreview.Size = new Size(sp.Size.Width, sp.Size.Height);

            // Setup the output video resolution file as the preview
            _job.OutputFormat.VideoProfile.Size = new Size(sp.Size.Width, sp.Size.Height);

            // Display the video device properties set
            //toolStripStatusLabel1.Text = sp.Size.Width.ToString() + "x" + sp.Size.Height.ToString() + "  " + sp.FrameRate.ToString() + " fps";

            // Sets preview window to winform panel hosted by xaml window
            _deviceSource.PreviewWindow = new PreviewWindow(new HandleRef(panelVideoPreview, panelVideoPreview.Handle));

            // Make this source the active one
            _job.ActivateSource(_deviceSource);
        }

        void StopJob()
        {
            // Has the Job already been created ?
            if (_job != null)
            {
                _job.StopEncoding();

                // Remove the Device Source and destroy the job
                _job.RemoveDeviceSource(_deviceSource);

                // Destroy the device source
                _deviceSource.PreviewWindow = null;
                _deviceSource = null;
            }
        }

        private void cmdGrabImage_Click(string tapId)
        {
            if (InvokeRequired)
            {
                BeginInvoke(new MethodInvoker(() => cmdGrabImage_Click(tapId)));
                return;
            }

            // Create a Bitmap of the same dimension of panelVideoPreview (Width x Height)
            // using (Bitmap bitmap = new Bitmap(panelVideoPreview.Width, panelVideoPreview.Height))
            using (Bitmap bitmap = new Bitmap(panelVideoPreview.Width, panelVideoPreview.Height))
            {
                using (Graphics g = Graphics.FromImage(bitmap))
                {
                    // Get the paramters to call g.CopyFromScreen and get the image
                    Rectangle rectanglePanelVideoPreview = panelVideoPreview.Bounds;
                    Point sourcePoints = panelVideoPreview.PointToScreen(new Point(panelVideoPreview.ClientRectangle.X, panelVideoPreview.ClientRectangle.Y));
                    g.CopyFromScreen(sourcePoints, Point.Empty, rectanglePanelVideoPreview.Size);
                }

                //string strGrabFileName = string.Format("F:\\Snapshot_{0:yyyyMMdd_hhmmss}.jpg", DateTime.Now);

                Image thumb = bitmap.GetThumbnailImage(160, 120, null, IntPtr.Zero);
                //thumb.Save(strGrabFileName, System.Drawing.Imaging.ImageFormat.Jpeg);

                MemoryStream ms = new MemoryStream();
                thumb.Save(ms, ImageFormat.Jpeg);

                using (var cn = new SqlConnection(_databaseConnection))
                {
                    cn.Open();
                    using (SqlCommand cmd = new SqlCommand("UPDATE CARD_TAP SET FOTO=@binaryValue WHERE ID=" + tapId, cn))
                    {
                        cmd.Parameters.Add("@binaryValue", SqlDbType.VarBinary, -1).Value = ms.ToArray();
                        cmd.ExecuteNonQuery();
                    }
                    cn.Close();
                }

                //var dt = new DataTable();
                //using (var da = new SqlDataAdapter("SELECT FOTO FROM CARD_TAP WHERE ID=" + tapId, _databaseConnection))
                //{
                //    da.Fill(dt);
                //}

                //if (dt.Rows.Count > 0)
                //{
                //    File.WriteAllBytes("F:\\AGUS.JPG", (byte[])(dt.Rows[0]["FOTO"]));
                //}

                var bmp = bitmap.GetThumbnailImage(bitmap.Width, bitmap.Height, null, IntPtr.Zero);

                Rectangle cropRect = new Rectangle(200, 0, 300, panelVideoPreview.Height);
                Bitmap cropped = new Bitmap(label2.Width, label2.Height);
                using (Graphics g = Graphics.FromImage(cropped))
                {
                    g.DrawImage(bmp, new Rectangle(0, 0, cropped.Width, cropped.Height),
                                     cropRect, GraphicsUnit.Pixel);
                }

                label2.Text = "";
                label2.BackgroundImage = cropped;
                Application.DoEvents();
                panelVideoPreview.BackgroundImage = bmp;
                Application.DoEvents();
                _deviceSource.PreviewWindow = null;

                Thread t = new Thread(()=> { freezeImages(bmp); });
                t.Name = "AAAAA";
                t.IsBackground = true;
                t.Start();
            }
        }

        private void freezeImages(object image)
        {
            if (InvokeRequired)
            {
                BeginInvoke(new MethodInvoker(() => freezeImages(image)));
                return;
            }
            Thread.Sleep(900);
            _deviceSource.PreviewWindow = new PreviewWindow(new HandleRef(panelVideoPreview, panelVideoPreview.Handle));
            label2.BackgroundImage = null;
            label2.Text = TEMPEL_KARTU;
            resetLabelAbsen();
        }



        #endregion

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            StopJob();
            _rawinput.KeyPressed -= OnKeyPressed;
        }

        private void iklan2_Paint(object sender, PaintEventArgs e)
        {

        }

        private void Form1_FormClosed(object sender, FormClosedEventArgs e)
        {
            Log.Info("ABSEN APP EXITER");
        }

        Process _keyboardProc;

        private void pictureBox1_Click(object sender, EventArgs e)
        {
            string progFiles = @"C:\Program Files\Common Files\Microsoft Shared\ink";
            string keyboardPath = Path.Combine(progFiles, "TabTip.exe");

            _keyboardProc = Process.Start(keyboardPath);
        }

        private void timer3_Tick(object sender, EventArgs e)
        {
            //label8 panel1
            if (label8.Right > panel1.Left)
            {
                label8.Left -=5;
            }
            else
            {
                label8.Left = panel1.Right;
            }
        }
    }

    public static class Log
    {
        private static ILog log => LogManager.GetLogger(new StackFrame(2).GetMethod().DeclaringType);

        public static void Error(object message) => log.Error(message);

        public static void Error(Exception ex) => log.Error(ex.Message, ex);

        public static void Error(string format, params object[] param) => log.Error(string.Format(format, param));

        public static void Error(Exception ex, string format, params object[] param) => log.Error(string.Format(format, param), ex);

        public static void Info(object message) => log.Info(message);

        public static void Info(string format, params object[] param) => log.InfoFormat(format, param);

        public static void Debug(object message) => log.Debug(message);

        public static void Debug(string format, params object[] param) => log.DebugFormat(format, param);

        public static void Warn(object message) => log.Warn(message);

        public static void Warn(string format, params object[] param) => log.WarnFormat(format, param);
    }
}
